package yolo

import (
	"appengine"
	"appengine/urlfetch"
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"regexp"
	"runtime"
	"strconv"
	"time"
)

type yoloErrorString string
type YoloError struct {
	file string
	line int
	message string
}

func (e YoloError) Error() string {
	return fmt.Sprintf("%s:%v: %Ts", e.file, e.line, e.message)
}

func NewYoloError(msg string) YoloError {
	_, file, line, _ := runtime.Caller(1)
	return YoloError{file:file, line:line, message:msg}
}

func YoloHTTPStatusError(status int) YoloError {
	msg := fmt.Sprintf("YoloError: got HTTP status %v", status)
	_, file, line, _ := runtime.Caller(1)
	return YoloError{file:file, line:line, message:msg}
}

var (
	YoloDeadlineError = NewYoloError("YoloError: DEADLINE_EXCEEDED")
)

type CountMap struct {
	Key   string
	Count int64
}

type CountMapArray struct {
	counts []*CountMap
}

func (c *CountMapArray) Len() int           { return len(c.counts) }
func (c *CountMapArray) Less(i, j int) bool { return c.counts[i].Count > c.counts[j].Count }
func (c *CountMapArray) Swap(i, j int)      { c.counts[i], c.counts[j] = c.counts[j], c.counts[i] }

func min(x, y int) int {
	if x < y {
		return x
	}
	return y
}

func max(x, y int) int {
	if x > y {
		return x
	}
	return y
}

func decodeJSONInt64Array(value interface{}) []int64 {
	vs := value.([]interface{})
	decoded := make([]int64, len(vs))
	for i, v := range vs {
		switch vv := v.(type) {
		case int:
			decoded[i] = int64(vv)
		case int64:
			decoded[i] = vv
		case float64:
			decoded[i] = int64(vv)
		}
	}
	return decoded
}

func currentLocation() string {
	_, file, line, _ := runtime.Caller(1)
	return fmt.Sprintf("%s:%v", file, line)
}

func getFormValueInt(r *http.Request, key string, defaultValue int) int {
	value := r.FormValue(key)
	if value == "" {
		return defaultValue
	}
	v, err := strconv.Atoi(value)
	if err == nil {
		return v
	}
	return defaultValue
}

func makeSnippet(text string, max int, ellipsis string) string {
	if len(text) <= max {
		return text
	}
	return text[:max] + ellipsis
}

func loadJSONURL(c appengine.Context, requestURL string, data interface{}) error {
	client := urlfetch.Client(c)
	resp, err := client.Get(requestURL)
	if err != nil {
		if err.Error() == "DEADLINE_EXCEEDED" {
			return YoloDeadlineError
		}
		return err
	}
	if resp.StatusCode != 200 {
		c.Errorf("%s", requestURL)
		return YoloHTTPStatusError(resp.StatusCode)
	}
	body, _ := ioutil.ReadAll(resp.Body)
	return json.Unmarshal(body, data)
}

func getYMD(dt time.Time) string {
	return dt.Format("20060102")
}

func getHms(dt time.Time) string {
	return dt.Format("150405")
}

var sanitizeEmailRegexp = regexp.MustCompile(`([a-zA-Z._%]+)[+\-]?[^@]*(@[a-zA-Z.\-]+)`)

func sanitizeEmail(email string) string {
	m := sanitizeEmailRegexp.FindStringSubmatch(email)
	if m != nil {
		return m[1] + m[2]
	}
	return email
}
